using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using Impact.Infrastructure.Configuration;
using StructureMap;
using System.Configuration;

namespace Impact.Infrastructure.Plugins
{
    /// <summary>
    /// PluginCache loads all plugins defined in the config, and caches them for 
    /// use in the application.
    /// </summary>
    public class PluginCache : IEnumerable
    {
        /// <summary>
        /// dictionary of available plugins, hashed by the Guid that uniquely identifies
        /// each plugin class
        /// </summary>
        private Dictionary<Guid, IImpactPlugin> _plugins;

        /// <summary>
        /// static instance of the cache for singleton
        /// </summary>
        private static PluginCache _cache = new PluginCache();

        /// <summary>
        /// Gets the singleton instance of the PluginCache object
        /// </summary>
        public static PluginCache Instance
        {
            get { return _cache; }
        }

        /// <summary>
        /// internal constructor - loads the list of configured plugins, instantiates them and
        /// loads them into the cache
        /// </summary>
        protected PluginCache()
        {
            _plugins = new Dictionary<Guid, IImpactPlugin>();


            ImpactSettings appConfig = ObjectFactory.GetInstance<IConfigProvider>().Settings;
            PluginSettingsCollection settings = appConfig.Plugins;

            foreach (PluginSettings pluginSettings in settings)
            {
                Type pluginType = Type.GetType(pluginSettings.Type);
                if ( pluginType != null )
                {
                    IImpactPlugin plugin = (IImpactPlugin)Activator.CreateInstance( pluginType );
                    _plugins.Add( plugin.PluginId, plugin );
                }
                else
                {
                    throw new ConfigurationErrorsException(
                        string.Format( "Could not load plugin of type: {0}", pluginSettings.Type ) );
                }
            }

        }

        /// <summary>
        /// Retrieve the plugin associated with the unique Guid
        /// </summary>
        /// <returns>an object that conforms to the IImpactPlugin interface</returns>
        public IImpactPlugin GetPlugin(Guid key)
        {
            if ( _plugins.ContainsKey( key ) )
            {
                return _plugins[key];
            }
            else
            {
                throw new ArgumentException( string.Format( "Plugin has not been loaded: {0}", key ) );
            }
        }

        /// <summary>
        /// Retrieve the enumerator to loop through all plugins in the cache
        /// </summary>
        public List<IImpactPlugin>.Enumerator GetEnumerator()
        {
            return new List<IImpactPlugin>(_plugins.Values).GetEnumerator();
        }

        #region IEnumerable Members

        /// <summary>
        /// Retrieve the enumerator to loop through all plugins in the cache
        /// </summary>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _plugins.Values.GetEnumerator();
        }

        #endregion
    }
}
